Skip to content

C# 由 C 和 C++ 衍生而来,优化了两者的安全性问题,如:鼠标状态读取、内存读写。 C# 需要依赖环境运行,如 .NET Framework(windows平台)、.NET Core(跨平台)。

数据类型

值类型

数据由二进制来转换单位,最小的单位是 '位' 。 不同的数据结构,占用的位数不同,位数越多该数据结构占用越大。

	Bool(1位|布尔值):true/false   默认false
	Byte(8位|字节):0 - 255   默认0
	char(16位|Unicode字符):U+0000 - U+ffff   默认'/0'
	double(64位|双精度浮点):(-7.9*10**28 - 7.9*10**28)/(10**0 - 10**28)   默认0.0D
	float(32位|单精度浮点):(+/-)5.0*10**-324 - (+/-)1.7*10**308   默认0.0F
	short(16位|有符号整数类型):-32,768 - 72,767   默认0
	int(32位|有符号整数类型):-2,147,483,648 - 2,147,483,647   默认0
	long(64位|有符号整数类型):-2^63 - 2^63-1   默认0
枚举enum

一般用于定义类型 枚举是一组自定义名词的整形常量

cs
enum 枚举类型名
{
	枚举值1,
	枚举值2,
	枚举值列表
}

// 使用
枚举值类型 变量名 = 枚举值类型.枚举值;
结构体struct

结构体可以创建多个数据结构 类似对象的类型定义

cs
struct 结构体名词
{
	public 类型 结构体元素1;
	public 类型 结构体元素2;
}

// 使用1
结构体名词 变量名 = new 结构体名词();
变量.结构体元素1 = 值;
变量.结构体元素2 = 值;

// 使用2
结构体名词 变量名 = new 结构体名词
{
	结构体元素1 = 值,
	结构体元素2 = 值,
}
运用 - 值类型的运算

运算主要分为数学运算、比较运算、逻辑运算。

cs
位运算 - 与运算(同位均为真,则为真)
	// 001
	int a = 1
	// 010
	int b = 2
	// 000
	a & b == 0

位运算 - 或运算(同位有真,则为真)
	// 001
	int a = 1
	// 010
	int b = 2
	// 011
	a | b == 3

引用类型

字符串

字符串是一个类,因为c#的优化处理,所以不用new 单引号,字符 双引号,字符串

cs
string str = "abc";

str[索引]  // 可以通过索引查看,但不能修改
str += "d";  // 可以+=运算
cs
// 静态函数
	String.Concat(string,string,...)  // 返回:字符串,拼接

// 公共函数
	.Contains(string);  // 返回:布尔值,是否包含【某些】字符串
	.Remove(int);  // 返回:字符串,从索引【几】开始删除
	.Remove(int,int);  // 返回值:字符串,从索引【几】开始删除【几】位
	.Substring(int);  // 返回:字符串,从索引【几】开始获取
	.Substring(int,int);  // 返回:字符串,从索引【几】开始获取【几】位
	.Insert(int,string);  // 返回值:字符串,从索引【几】开始添加【某些】字符串
	.Replace(string,string);  // 返回值:字符串,将所有【某些】字符串替换成【某些】字符串
	.Split(string);  // 返回值:字符串[],将【某些】字符串视作分隔符
字符串工具 StringBuilder

用于解决字符串改变时,旧字符的内存不会销毁的问题。

cs
    StringBuilder 工具 = new StringBuilder(字符串);
    工具.Append(字符串);  // 追加
    string 字符串 = 工具.ToString();

	.Append()  // 追加
	.Insert()  // 同字符串
	.Remove()
	.Replace()
	.ToString()  // 强制转换成字符串
数组

创建后不能动态调整长度

	类型[] 数组名 = new 类型[长度];
	类型[] 数组名 = new 类型[长度]{元素1, 元素2, ..., 元素n};
	类型[] 数组名 = {元素1, 元素2, ..., 元素n};
	int[] age = new int[5]{1,2,3,4,5};

注:未定义元素时,元素为默认值;未定义长度时,长度为元素数。
注:元素数和长度不等时,报错。
运用 - 二维数组
	类型[,] 数组名 = new 类型[外层长度,内层长度]{数组1,数组2};
	int[,] ages = new int[2,3]{{1,2,3}, {1,2,3}};
类 class

类体现了编程的面向对象思想。 注:不同参数类型数量的方法,可以共存。

cs
class 类名
{
	public 值类型 属性名;
	public 返回值类型 方法名()
	{
		方法体;
		this.属性;
		this.方法(); // 可通过this关键字,调用实例的属性方法
	}
}

// 调用 - 创建实例
类名 实例名 = new 类名();
实例名.属性名 = 值;

// 调用 - 创建并定义实例
类名 实例名 = new 类名()
{
	属性名 = 值;
};

// 调用实例
实例名.属性;
实例名.方法();
运用 - 类的属性私有化

用于封装属性值的读取和修改 一般名字和属性相同,首字母大写

cs
class 类名
{
	private string name;  // 修饰符要更改为私域
	public string Name
	 {
		 get // 没有get方法则不可访问
		 {
			 return name; 
			 return "私密信息不可访问"  // 也可用于鉴权,等其他运算
		 }
		 
		set // 没有set方法则不可修改
		{
			subName = value;  // value是关键字,表示被赋值的值
			Console.WriteLine("狗贼xxx试图修改密码");  // 也可用于鉴权
		}
	}
}

// 简写
class 类名
{
	private string name;
	public string Name {get; set; }  // 默认的改查方法,注:指向Name,而非name
	public string Name {get; }  // 只读
}
运用 - 类的构造方法

构造方法名和类名相同 构造方法在实例创建的时候使用,并且没有返回值

cs
class 类名
{
	public string name;
	public 类名(name)
	{
		this.name = name
	}

	public 类名(形参): this(name)  // 通过选择同样的参数名,实现重载
	{
		// 重载的代码
	}
}

// 创建实例时,参数写在类名里
类名 实例名 = new 类名(实参);
运用 - 类的析构 ~

析构方法名在类名前加波浪号,在实例被销毁时调用 一般用于清空,比如将某些引用类型的值赋值为null

cs
class 类名
{
	public string name;

	~类名()
	{
		Array = null;
		name = null;
	}
}
运用 - 类的静态属性

通过关键字static修饰,给类添加属性方法,而不是给实例写属性方法 静态属性是class里唯一的

cs
class
{
	public static 类型 静态属性名 = 值;
	public static 返回值 静态方法名()
	{
		// 函数体
	}
} 

// 调用
类.静态属性名
运用 - 静态类 static

通过关键字 static 修饰类 静态类里只能包含静态成员

cs
static class 类名
{
	public static 类型 静态属性名 = 值;
	
	static 类名()  // 静态的构造方法不可有参数,只会在首次使用时调用
	{
		// 构造方法
		// 一般用于给静态属性赋值
	}
}
运用 - 抽象类 abstract

通过关键字 abstract 修饰类 抽象类本身不可被构造,主要用于继承 可以理解成,把一些相同特质的类,抽象出一个父级来概括

cs
abstract class 抽象类
{
	// code
	public abstract void 抽象方法();  // 抽象方法没有函数体,一般被用于继承者重写
} 

// 继承
class 子类:抽象类
{
	public override void 重写()  // 修饰符同虚方法,用于继承
	{
		// 函数体
	}
运用 - 类的继承

子类具备父类的全部内容,并且具备其独特的内容 例如:父类 - 家电,子类 - 冰箱

cs
class 子类: 父类
{
	// 属性、 方法
	base.方法();  // 可通过base关键字,调用父类方法
}

// 创建实例时,父类可以指向子类
父类 实例名 = new 子类();
运用 - 类方法的重写(虚方法)

子类的方法和父类方法名相同

cs
// 通过关键字 new 来重写(不推荐)
class 父类
{
	public void 方法名()
	{
		内容
	}
}

class 子类: 父类
{
	public new void 方法名()
	{
		内容
	}
}

// 通过虚方法来重写
class 父类
{
	public virtual void 方法名()
	{
		内容
	}
}

class 子类: 父类
{
	public override void 方法名()
	{
		base.方法();  // 可通过base关键字,调用父类原本方法,然后再添加新内容
		内容
	}
}
接口 interface

包含事件、索引器、方法和属性,但不包含构造函数、析构函数、静态成员和常量。 接口负责定义,继承者负责实现(类似抽象)。 默认引用public

cs
interface 接口名
{
	// 内容
}

// 继承
class 子类: 基类, 接口1, 接口2  // 如果有基类,必须放首位
{
	// 内容
	// 接口的实现
}

类型转换

隐式转换 - 由小到大

主要看范围是否兼容转换前 位数从小到大可以正常转换,如 byte(8bit) -> int(32bit) √ 整数可以转换成小数,如 int -> double √ 有无符号不能正常转换,如 short(有符号) -> unit(无符号) ×

    byte b = 10;
    int i = b;
    double d = i;
强制转换 - 由大变小

一般用于范围由大变小,可能会丢失精度,需要调用方法强制转换。

方案1 - 通过括号快捷转换
    int age = 100;
    byte bage = (byte)age;

方案2 - 通过转换类Convert
	int age = 100;
    byte bage = Convert.ToByte(age);
强制转换 - 字符串和整型

数字 -> 字符串,变量.ToString()方法 字符串 -> 数字,类型.Parse(目标)方法

cs
数字 -> 字符串
	int age = 100;
    string bage = age.ToString();

字符串 -> 数字
	string str = 100;
	int num = int.Parse(str);
注:不能转换时会报错
强制转换 - 装箱与拆箱

值类型可以装箱成引用类型,如 int -> object 通过拆箱,可以将该引用类型重新转换回值类型。

装箱
	int i = 3;
	object o = i;

拆箱
	int b = (int)o;

变量

常量

运行时不可别改变。

	整数:1
	浮点:1.1f
	字符:'a'
	字符串:'abc'
变量

运行时可被改变,需先被声明类型。

	类型 变量名 = 值;
	Byte x = 1;

函数(静态)

cs
// 创建函数
static 返回值类型 方法名(参数类型 参数,参数2类型 参数2 = 缺省值) 
{
	函数体;
	return 返回值;
}

// 调用方法
方法名(参数);

// 泛型
运用 - 实参改变 ref

通过关键字修饰参数,将参数的值类型改成引用类型。 基于底层,作为参数的引用类型可在函数中改变。 例:可以用于交换这个场景。

cs
static 返回值类型 方法名(ref 参数类型 参数1,ref 参数2类型 参数2) 
{
	var 临时变量 = 参数1;
	参数1 = 参数2;
	参数2 = 临时变量;
}
// 调用
方法名(ref 参数1, ref 参数2);
运用 - 光速赋值 out

通过关键字修饰参数,直接给实参赋值。 有点类似 变量 = 函数(变量) 的语法糖。

cs
static 返回值类型 方法名(out 参数类型 参数名)
{
	out参数 = out值;
	return 返回值;
}
// 调用
变量类型 变量名;  // 可以不添加初始值
方法名(out 变量名)  // 将函数的out值 赋值 给变量
运用 - 泛型 T

通过标识符,来假定参数类型 例:可以用于交换这个场景(省略对类型的重载)

cs
static 返回值类型 方法名<T, 泛型2>(T 参数1, T 参数2, 泛型2 参数3)  // 泛型名称自己定义
{
	// 函数体
	T newVal = 参数2;
	参数2 = 参数1;
	参数1 = newValue;  // 如果用于交换,参数一般添加ref关键字
}

// 调用
方法<类型>();  // 可不写类型
cs
// 对泛型的约束
static 返回值类型 方法名<T, U>(T 参数1, U 参数2)where T: struct
	where U: class, new()  // 多个泛型可以换行添加,多种约束可以逗号
{
	// 内容
}

// 约束的类型
	struct  // 值类型(数字布尔值等)
	class  // 引用类型
	new()  // 具有一个无参数的构造方法
	基类  // 参数是基类或其派生类
	接口  // 实现了该接口的类型

委托 delegate

通过关键字 delegate ,定义(委托)方法类型 委托用于解决,方法传递的问题 例:监听场景,主程序执行过程中,需要让某个组件执行异步函数

cs
// 1. 定义委托类型
public delegate void 委托类型();

// 2. 声明委托变量
委托类型 委托;  // 声明空指向
委托类型 委托 = new 委托类型(方法名);  // 声明并添加委托
委托类型 委托 = 方法名;  // 声明并添加委托的语法糖

// 3. 保存方法;
委托 = 方法名;  // 赋值
委托 += 方法名; // 追加委托,先调用之前的,再调用之后的
委托 -= 方法名;  // 取消委托
匿名委托

使用委托时,方法名省略的一种写法

cs
委托 += delegate(参数类型 参数,...){
	// 函数体
}

// 语法糖,省略了关键字 和 参数类型
委托 += (参数1,...) => {
	// 函数体
}

// 语法糖, 只有单个参数时,省略括号
委托 += 参数 => {
	// 函数体
}
事件声明 event

在声明委托变量时,通过添加关键词event,表示该委托是个事件 事件在非所在类中,不可赋值,不可调用(允许追加和减少)

cs
// 声明委托
public 委托类型 委托名;

// 声明事件
public event 委托类型 委托名;

集合

集合类似于C#内置的构造函数。 实现了ICollection、Ilist、Ienumerable接口。 集合可以动态调整长度,元素的类型可不同(因此不安全)。 利用集合的方法来实现多种复杂的功能。

	非泛型集合:System.Collections
	泛型集合:System.Collections.Generic
数组 ArrayList
cs
using System.Collections;

ArrayList 数组名 = new ArrayList();

	.Add(追加元素);  // push
	.Insert(索引, 插入元素);  // 插入
	.Remove(删除元素);  // 删除(首个对应元素)
	.RemoveAt(索引);  // 删除
	.Clear();  // 清空
	.Reverse();  // 反向排序
	.Contains(查找元素);  返回值: bool  // 查询是否存在
数组泛型 List

限制了元素类型

cs
using System.Collections.Generic;

List 数组名<类型> = new List<类型>();
堆栈 Stack

后进先出 常使用于,对顺序要求不严格的场景,例:只需遍历全部

cs
using System.Collections;

Stack 堆栈 = new Stack();

	.Push(追加元素);
	.Pop(); 返回值: object // 出栈,返回装箱的元素
	.Peek(); 返回值: object // 查看
	.Contains(查找元素);  返回值: bool  // 查询是否存在
	.Clear();  // 清空
	.Count;  // 长度
堆栈泛型 Stack

限制了元素类型

cs
using System.Collections.Generic;

Stack 堆栈<类型> = new Stack<类型>();
队列 Queue

先进先出 常用于,优化性能,例:关闭开启时非销毁创建,而是利用队列隐藏显示

cs
using System.Collections;

Queue 队列 = new Queue();

	.Enqueue(追加元素);  // 入列push
	.Dequeue(); 返回值: object // 出列shift,返回第一个
	.Peek(); 返回值: object // 查看
	// 其他类似堆栈
队列泛型 Queue

限制了元素类型

cs
using System.Collections.Generic;

Queue 队列<类型> = new Queue<类型>();
哈希表 Hashtable

无序,键值对

cs
using System.Collections;

Hashtable ht = new Hashtalbe();

	.Add(键, 值);  // 追加
	ht[键] = 值;  // 增改
	ht[键]  // 查找对应值(无则返回null)
	.Remove(键)  // 删除
	.ContainsKey(寻找键);  返回值: bool  // 查询是否存在
	.ContainsValue(寻找值);  返回值: bool  // 查询是否存在
	
	.Keys;  返回值: object[]  // 键数组,可通过foreach循环
	.Values;  返回值: object[]  // 值数组,同上
字典泛型 Dictionary

限制了元素类型 TryGetValue方法是字典独有的

cs
using System.Collections.Generic;

Dictionary 字典<键类型, 值类型> = new Dictionary<键类型, 值类型>();

// 字典[键] 的上位替代,解决因键不存在导致的报错   返回值: bool
值类型 value;
bool res = 字典.TryGetValue(键,out value);
if(res){
	// 取值成功
}
else{
	// 取值失败
}

其他关键字

访问修饰符

在类的变量或方法前面添加修饰符

cs
class 类名
{
	修饰符 类型 属性名;
}
public最大级

该修饰符的范围最广 允许其他的代码块中都可以调用

private类级

仅在当前类里,可访问其中成员

protected类及子集

在当前类,及其子类中,允许访问其中成员

internal文件级

仅在当前文件中,可访问其中成员

命名空间

类似于作用域,用于解决名词重复的问题

cs
namespace 空间名称
{
	// 代码
}

// 调用 - 在当前名称空间内创建另一个名词空间的类的实例
另一个空间.类名 实例名 = new 另一个空间.类名();

// 调用2(常用) - 在顶部使用using
using 另一个空间名词
类名 实例名 = new 类名();

执行顺序

分支结构
cs
if(布尔值)
{语句}
else if(布尔值)
{语句}
else
{语句}

switch (reply)
{
    case "消耗品":
        {
	        return;
	    }
}
循环
cs
while(终止条件)
{
	语句
	continue 跳出当次循环
	break 跳出循环
}

do
{
	语句
	continue 跳出当次循环
	break 跳出循环
}while(终止条件)

for(定义变量;终止条件;循环后执行)
{
	语句
	break 跳出循环
}

foreach(迭代元素类型或var 定义变量名 in 迭代集合)
{
	语句
}

常用方法

常用函数(控制台)

	System.Console.Writeline()
	作用:将参数打印至控制台
	参数:需要打印的内容

	System.Console.Read()
	作用:读取用户输入在控制台的内容,输入一个字符后执行剩余代码
	参数:/

	System.Console.ReadLine()
	作用:读取用户输入在控制台的内容,回车后执行剩余代码
	参数:/

	System.Console.ForegroundColor = ConsoleColor.颜色;
	作用:改变控制台文字的颜色

类型判断

cs
变量 is 类型  // 布尔值

随机数 Random

cs
new Random().Next(5, 10);  // 参数1,最小值;参数2,最大值

休眠 Thread

cs
Thread.Sleep(1000);  // 参数,毫秒